using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

namespace Super
{
	public class PanelManager : SimpleSingle<PanelManager>
	{
		public Dictionary<string, PanelBase> panelDict = new Dictionary<string, PanelBase>();
		public LinkedList<PanelBase> panelList = new LinkedList<PanelBase>();
		public override void OnInit()
		{
			base.OnInit();
		}

		public static T OpenPanel<T>(params object[] args) where T : PanelBase
		{
			string panelName = typeof(T).Name;
			PanelBase panelBase = PanelManager.FindPanel(panelName);
			if (panelBase == null)
			{	
				string addr = (string)typeof(T).GetField("addr").GetValue(null);
				GameObject prefab = AssetUtil.LoadAsset<GameObject>(addr);

				GameObject GO = GameObject.Instantiate(prefab, Vector3.zero, Quaternion.identity);
				GO.name = panelName;

				panelBase = GO.GetComponent<PanelBase>();
				string parentName = panelBase.canvas.sortingLayerName;
				parentName = parentName.StartsWith("UI") ? parentName : "UINormal";

				Transform rootTF = FWRefManager.Ins.UIRootTF;
				GO.transform.SetParent(rootTF.Find(parentName), true);
			}
			panelBase.gameObject.SetActive(true);
			panelBase.transform.SetAsLastSibling();
			Transform parent = panelBase.transform.parent;
			if (parent != null && parent.name.StartsWith("UI"))
			{
				panelBase.GetComponent<Canvas>().sortingLayerName = parent.name;
			}

			panelBase.Open(args);
			Ins.panelDict[panelName] = panelBase;
			if (Ins.panelList.Contains(panelBase))
				Ins.panelList.Remove(panelBase);
			Ins.panelList.AddLast(panelBase);
			Ins.UpdateInfo();

			EventManager.Emit(new PanelOpenGE(panelName, panelBase));
			return (T)panelBase;
		}

		public static void ClosePanel<T>() where T : PanelBase
		{
			string panelName = typeof(T).Name;
			PanelBase panel = FindPanel(panelName);
			if (panel != null && panel.gameObject.activeSelf)
			{
				panel.gameObject.SetActive(false);
				panel.Close();
			}
		}
		
		public static void CloseAllPanel()
		{
			List<string> panelNames = new List<string>(Ins.panelDict.Keys);

			foreach (var panelName in panelNames)
			{
				PanelBase panel = Ins.panelDict[panelName];
				if (panel != null && panel.gameObject.activeSelf)
				{
					panel.gameObject.SetActive(false);
					panel.Close();
				}
			}
		}

		public void OnClosePanel(string panelName)
		{
			if (!panelDict.ContainsKey(panelName)) return;

			PanelBase panelBase = panelDict[panelName];
			panelList.Remove(panelBase);
			UpdateInfo();
			EventManager.Emit(new PanelCloseGE(panelName));
		}

		public void ClearPanel()
		{
			List<string> panelNames = new List<string>(panelDict.Keys);

			foreach (var panelName in panelNames)
			{
				PanelBase panel = panelDict[panelName];
				if (panel == null) continue;
				if (panel.gameObject.activeSelf)
				{
					panel.Close();
				}
				GameObject.Destroy(panel.gameObject);
			}

			panelDict.Clear();
			panelList.Clear();
		}

		private void UpdateInfo()
		{
			LinkedListNode<PanelBase> curNode = panelList.First;
			int order = 0;
			while (curNode != null)
			{
				LinkedListNode<PanelBase> next = curNode.Next;
				if (curNode.Value != null)
				{
					curNode.Value.canvas.sortingOrder = order++;
				}
				else
				{
					panelList.Remove(curNode);
				}

				curNode = next;
			}

			List<string> panelNames = new List<string>(panelDict.Keys);
			foreach (var panelName in panelNames)
			{
				if (panelDict.ContainsKey(panelName) && panelDict[panelName] == null)
				{
					panelDict.Remove(panelName);
				}
			}
		}


		public static PanelBase FindPanel<T>() where T : PanelBase
		{
			string panelName = typeof(T).Name;
			return FindPanel(panelName);
		}

		public static PanelBase FindPanel(string panelName)
		{
			PanelBase panelBase = null;
			if (Ins.panelDict.ContainsKey(panelName))
			{
				panelBase = Ins.panelDict[panelName];
				if (panelBase == null)
				{
					Ins.panelDict.Remove(panelName);
				}
			}

			return panelBase;
		}

		public static bool CheckIfPanelVisible(string panelName)
		{
			PanelBase panelBase = FindPanel(panelName);
			if (panelBase != null && panelBase.gameObject.activeSelf)
			{
				return true;
			}
			return false;
		}

		public static bool CheckIfPanelVisible<T>() where T : PanelBase
		{
			string panelName = typeof(T).Name;
			return CheckIfPanelVisible(panelName);
		}

		public static void SetPanelBehind(PanelBase targetPanel, PanelBase behindPanel)
		{
			if (targetPanel == null && behindPanel == null) return;

			var behindNode = Ins.panelList.Find(behindPanel);
			var targetNode = Ins.panelList.Find(targetPanel);
			if (behindNode == null || targetNode == null) return;

			Ins.panelList.Remove(behindNode);
			Ins.panelList.AddBefore(targetNode, behindNode);
			Ins.UpdateInfo();
		}
	}

}
